package com.atwisdom.star.dcs.service.Impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import com.atwisdom.star.dcs.dao.RealTimeInfoMinuteDao;
import com.atwisdom.star.dcs.dao.RealTimeInfoTempDao;
import com.atwisdom.star.dcs.pojo.RealTimeInfo;
import com.atwisdom.star.dcs.pojo.RealTimeInfoMinute;
import com.atwisdom.star.dcs.pojo.RealTimeInfoTemp;
import com.atwisdom.star.dcs.service.RealTimeMinuteStatService;
import com.atwisdom.star.dcs.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class RealTimeMinuteStatServiceImpl implements RealTimeMinuteStatService {
    @Autowired
    private RealTimeInfoTempDao realTimeInfoTempDao;

    @Autowired
    private RealTimeInfoMinuteDao realTimeInfoMinuteDao;

    /**
     * 获取分钟表最后一个统计数据，时间作为结束时间，开始时间-1分钟为开始时间，如果分钟表不存在数据则开始时间为临时表最早采集数据的采集时间
     * 如果开始时间小于在当前时间之前，进入循环，统计分钟表数据
     * 结束时间为开始时间+1分钟，如果在开始时间之前不存在临时数据则跳出循环
     *
     * @Param []
     * @Author why
     * @Date 2024/7/5
     **/
    @Override
    public void realTimeDataStat() {
        long currentTimestamp = DateUtils.getMinuteTimestamp(System.currentTimeMillis());
        List<String> names = realTimeInfoTempDao.queryPointNames();
        for (String name : names) {
            //asc
            RealTimeInfoTemp realTimeInfoTemp = realTimeInfoTempDao.findOne("name=='" + name + "'", "pickTimestamp," +
                    "asc");
            if (realTimeInfoTemp == null) {
                continue;
            }
            long startTimestamp = DateUtils.getMinuteTimestamp(realTimeInfoTemp.getPickTimestamp());
            //desc
            RealTimeInfoMinute realTimeInfoMinute = realTimeInfoMinuteDao.findOne("name=='" + name + "'",
                    "endTimestamp,desc");
            if (realTimeInfoMinute != null) {
                long endTimestamp = realTimeInfoMinute.getEndTimestamp();
                startTimestamp = DateUtils.getMinuteTimestamp(endTimestamp)+1000*60;
            }

            while (startTimestamp < currentTimestamp) {
                long endTimestamp = startTimestamp+1000*60;
                String  condition = "name=='" + name + "'&& pickTimestamp > '"+ startTimestamp +"'";
                //asc
                RealTimeInfoTemp  realTimeInfo = realTimeInfoTempDao.findOne(condition, "pickTimestamp,asc");
                if (realTimeInfo == null) {
                    break;
                }
                buildRealTimeMinuteStat(name, startTimestamp, endTimestamp);
                startTimestamp = startTimestamp+1000*60;
            }
        }
    }

    /**
     * 根据点位，开始和结束时间，获取临时表开始和结束的数据，处理为分钟表数据
     *
     * @Param [name, startTimestamp, endTimestamp]
     * @Author gsh
     * @Date 2024/7/5
     **/
    private void buildRealTimeMinuteStat(String name, long startTimestamp, long endTimestamp) {
        //asc
        RealTimeInfoTemp startRealTimeInfo = realTimeInfoTempDao.findOne("name=='" + name + "' &&pickTimestamp " +
                "between " +
                "'" + startTimestamp + "' and '" + endTimestamp + "'", "pickTimestamp,asc");
        //desc
        RealTimeInfoTemp endRealTimeInfo = realTimeInfoTempDao.findOne("name=='" + name + "' &&pickTimestamp " +
                "between " +
                "'" + startTimestamp + "' and '" + endTimestamp + "'", "pickTimestamp,desc");
        if (endRealTimeInfo == null) {
            return;
        }
        RealTimeInfoMinute realTimeInfoMinute = new RealTimeInfoMinute();
        realTimeInfoMinute.setCode(endRealTimeInfo.getCode());
        realTimeInfoMinute.setCategory(endRealTimeInfo.getCategory());
        realTimeInfoMinute.setPf(endRealTimeInfo.getPf());
        realTimeInfoMinute.setName(endRealTimeInfo.getName());
        realTimeInfoMinute.setPv(endRealTimeInfo.getPv());
        realTimeInfoMinute.setStartTimestamp(startRealTimeInfo.getPickTimestamp());
        realTimeInfoMinute.setEndTimestamp(endRealTimeInfo.getPickTimestamp());
        realTimeInfoMinute.setStatTimestamp(startTimestamp);
        realTimeInfoMinute.setLastPv(startRealTimeInfo.getLastPv());
        double diffPv = endRealTimeInfo.getLastPv() - startRealTimeInfo.getLastPv();
        if(diffPv>0){
            realTimeInfoMinute.setDiffPv(diffPv);
            realTimeInfoMinute.setDuration(endRealTimeInfo.getPickTimestamp() - startRealTimeInfo.getPickTimestamp());
            realTimeInfoMinuteDao.save(realTimeInfoMinute);
        }
    }

    /**
     * 计算生产节拍
     * @param equipCode 设备编码，pCode:品番，statDate：日期
     * @return 返回生产节拍
     */
    @Override
    public Double calculateCycleCount(String equipCode,Date statDate) {
        LocalDate localStatDate = DateUtils.ConvertDateToLocalDate(statDate);
        LocalDateTime startDateTime = DateUtils.getLocalDateTime(localStatDate, "00:00:00");
        LocalDateTime endDateTime= DateUtils.getLocalDateTime(localStatDate, "23:59:59");
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = startDateTime.toInstant(offset).toEpochMilli();
        long endTimestamp = endDateTime.toInstant(offset).toEpochMilli();

        String nameA = equipCode + RealTimeInfo.JS_MARK + "A";
        String nameB = equipCode + RealTimeInfo.JS_MARK + "B";
        String name = equipCode + RealTimeInfo.JS_MARK;
        double diffPv = 0.0;
        double duration = 0;

        String condition = "{\"code\":\"" + equipCode + "\",\"name\":\"" + name + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoMinute> infoMinutes  = realTimeInfoMinuteDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            diffPv += infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
            duration += infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDuration).sum();
        }

        condition = "{\"code\":\"" + equipCode + "\",\"name\":\"" + nameA + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        infoMinutes  = realTimeInfoMinuteDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            diffPv += infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
            duration += infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDuration).sum();
        }

        condition = "{\"code\":\"" + equipCode + "\",\"name\":\"" + nameB + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        infoMinutes  = realTimeInfoMinuteDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            diffPv += infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
            duration += infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDuration).sum();
        }

        double minuteDuration = Math.floor(duration*100/(1000*60))/100.0;
        Double cycleCount;
        if(minuteDuration<1){
            cycleCount = 0.0;
        }else{
            cycleCount = Math.floor(diffPv*100/minuteDuration)/100.0;
        }
        return cycleCount;
    }

    /**
     * 按设备计数
     * @param equipCode 设备编码
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数统计
     */
    @Override
    public double getEquipCount(String equipCode, DateTime startTime,DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        double diffPv = 0.0;
        String condition = "{\"code\":\"" + equipCode + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoMinute> timeInfoMinutes  = realTimeInfoMinuteDao.query(condition);
        if(CollectionUtil.isNotEmpty(timeInfoMinutes)){
            diffPv += timeInfoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
        }
        return  diffPv;
    }


    /**
     * 按设备列表计数
     * @param equipCodes 设备编码列表
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数统计Map
     */
    @Override
    public Map<String,Double> queryEquipCount(List<String> equipCodes, DateTime startTime,DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        Map<String,Double> equipMap = new HashMap<>();
        equipCodes.forEach(code->{
            double diffPv = 0.0;
            String condition = "{\"code\":\"" + code + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
            List<RealTimeInfoMinute> timeInfoMinutes  = realTimeInfoMinuteDao.query(condition);
            if(CollectionUtil.isNotEmpty(timeInfoMinutes)){
                diffPv += timeInfoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
                equipMap.put(code,diffPv);
            }
        });
        return  equipMap;
    }

    /**
     *按设备品番计数
     * @param equipCode 设备编码
     * @param pCode 产品品番编号
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数统计
     * @return
     */
    @Override
    public double getEquipPfCount(String equipCode,String pCode, DateTime startTime,DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        double diffPv = 0.0;
        String condition = "{\"code\":\"" + equipCode + "\",\"pf\":\"" + pCode + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoMinute> timeInfoMinutes  = realTimeInfoMinuteDao.query(condition);
        if(CollectionUtil.isNotEmpty(timeInfoMinutes)){
            diffPv += timeInfoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
        }
        return  diffPv;
    }
}
